在前面我们学习了 CJSESM 的用法,除了语法的区别外,其实还存在一些其它的区别,

下面将详细介绍一下 加载时机导出内容文件命名 上的区别。

1 模块加载时机

因此 ESM 可以在代码执行前进行静态分析和优化,从而提高性能 (比如自动移除无用的死代码)。

CJS 需要等到代码运行时才能确定依赖关系和加载模块。

下面是一个具体的例子:从2个文件中分别导入1个函数,然后执行这2个导入的函数

1.1 ESM

```js // module1 console.log('load module1')

export function helloModule1() { console.log('hello module1') }

// module2 console.log('load module2')

export function helloModule2() { console.log('hello module2') }

// index.js import { helloModule1 } from './module1.js'

helloModule1()

import { helloModule2 } from './module2.js'

helloModule2() ```

1.2 CJS

```js // module1 console.log('load module1')

function helloModule1() { console.log('hello module1') }

module.exports = { helloModule1 }

// module2 console.log('load module2')

function helloModule2() { console.log('hello module2') }

module.exports = { helloModule2 }

// index.js const { helloModule1 } = require('./module1.js')

helloModule1()

const { helloModule2 } = require('./module2.js')

helloModule2() ```

执行结果如下。

2 导出内容的区别

ES Modules (ESM) 和 CommonJS (CJS) 在导入模块的对象引用上有不同的行为。

在 ESM 中,当我们导入一个变量时,实际上是导入了该变量的引用。这意味着,如果导出的变量在导入模块中发生了改变,导入的变量也会随之改变。

而在 CommonJS 中,导入的是导出模块的值的拷贝,而不是引用。这意味着,即使导出模块中的值发生了改变,导入模块中导入的变量不会受到影响。

简而言之,ESM 导入的是值的引用,而 CJS 导入的是值的拷贝

这是两者在模块导入中的一个重要区别,下面通过具体的例子感受一下。

2.1 ESM

```js // public.js export let num = 1

export function update() { num += 1 console.log('update num', num) }

// main.js import { num, update } from './public.js'

console.log(num) update()

console.log(num) update() ```

2.2 CJS

```js // public.js let num = 1

function update() { num += 1 console.log('update num', num) }

module.exports = { num, update }

// main.js const { num, update } = require('./public.js')

console.log(num) update()

console.log(num) update() ```

3 文件命名

通常情况下模块一般都以 .js 结尾,通过 package.json"type":"module" 区分模块类型,

实际上还可以通过文件命名来区分 .cjs 表明是 CJS 规范的模块,.mjs 表明是 ESM 规范的模块。

比如有如下 3 个文件,内容都是如下的 ESM 规范内容。

js // index.js // index.cjs // index.mjs import _ from 'fs' console.log('hello')

在没有 package.json 设置 "type":"module" 的前提下,只有 index.mjs 能成功执行。

.js.cjs 都会报错,且会提示 加载ESM资源需要 .mjs 结尾或 "type":"module"

小结

本节主要介绍了 CJS 与 ESM 之间的一些区别,包括 加载时机导出内容文件命名 上的区别: